package com.pudding;

import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author pudding
 * @Description: 增强版Windows窗口置顶和鼠标操作示例
 * @Date 2023/12/25
 */
public class Demo10 {
    // 扩展User32接口，添加更多Windows API功能
    public interface User32Extended extends StdCallLibrary {
        User32Extended INSTANCE = Native.load("user32", User32Extended.class);

        void SwitchToThisWindow(HWND hWnd, boolean fAltTab);
        int AllowSetForegroundWindow(int dwProcessId);
        boolean GetClientRect(HWND hWnd, RECT lpRect);
        boolean ClientToScreen(HWND hWnd, WinDef.POINT lpPoint);
        boolean SetCursorPos(int X, int Y);
        void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
        boolean SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
    }

    // RECT结构体定义
    public static class RECT extends Structure {
        public int left, top, right, bottom;

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("left", "top", "right", "bottom");
        }

        public static class ByReference extends RECT implements Structure.ByReference {}
    }

    // 鼠标事件常量
    private static final int MOUSEEVENTF_LEFTDOWN = 0x02;
    private static final int MOUSEEVENTF_LEFTUP = 0x04;
    private static final int MOUSEEVENTF_ABSOLUTE = 0x8000;

    // User32实例
    private static final User32 user32 = User32.INSTANCE;
    private static final User32Extended user32Extended = User32Extended.INSTANCE;
    
    // 日期格式化
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    // 计数器
    private static final AtomicInteger successCount = new AtomicInteger(0);
    private static final AtomicInteger failureCount = new AtomicInteger(0);

    /**
     * 激活并将窗口置顶
     * @param hwnd 窗口句柄
     * @return 是否成功
     */
    private static boolean activateWindow(HWND hwnd) {
        try {
            if (hwnd == null || hwnd.equals(null)) {
                return false;
            }

            // 获取进程ID并允许设置前台窗口
            IntByReference pid = new IntByReference();
            user32.GetWindowThreadProcessId(hwnd, pid);
            user32Extended.AllowSetForegroundWindow(pid.getValue());

            // 切换到目标窗口
            user32Extended.SwitchToThisWindow(hwnd, true);

            // 显示窗口
            user32.ShowWindow(hwnd, 9); // SW_RESTORE

            // 设置窗口位置（置顶）
            user32Extended.SetWindowPos(hwnd, new HWND(new com.sun.jna.Pointer(-1)),
                    0, 0, 0, 0,
                    0x0002 | 0x0001 | 0x0040); // SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW

            // 激活窗口
            user32.SetForegroundWindow(hwnd);
            user32.SetFocus(hwnd);

            // 等待窗口激活
            Thread.sleep(200);
            return true;
        } catch (Exception e) {
            logError("激活窗口时发生错误", e);
            return false;
        }
    }

    /**
     * 在窗口中心执行鼠标双击
     * @param hwnd 窗口句柄
     */
    private static void performMouseClick(HWND hwnd) {
        try {
            // 获取窗口客户区矩形
            RECT.ByReference rect = new RECT.ByReference();
            user32Extended.GetClientRect(hwnd, rect);

            // 计算中心点
            WinDef.POINT clientCenter = new WinDef.POINT(
                    rect.left + (rect.right - rect.left) / 2,
                    rect.top + (rect.bottom - rect.top) / 2
            );

            // 转换为屏幕坐标
            user32Extended.ClientToScreen(hwnd, clientCenter);

            // 移动鼠标到中心点
            user32Extended.SetCursorPos(clientCenter.x, clientCenter.y);

            // 执行双击
            for (int i = 0; i < 2; i++) {
                user32Extended.mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
                Thread.sleep(50);
                user32Extended.mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                if (i == 0) Thread.sleep(100);
            }
        } catch (Exception e) {
            logError("执行鼠标操作时发生错误", e);
        }
    }

    /**
     * 记录错误信息
     * @param message 错误消息
     * @param e 异常
     */
    private static void logError(String message, Exception e) {
        System.err.println(String.format("[%s] %s: %s",
                sdf.format(new Date()), message, e.getMessage()));
    }

    /**
     * 记录信息
     * @param message 信息
     */
    private static void logInfo(String message) {
        System.out.println(String.format("[%s] %s",
                sdf.format(new Date()), message));
    }

    public static void main(String[] args) {
        // 要查找的窗口标题
        String windowTitle = "YDZACXKF01813(c_guxianyang)";

        logInfo("程序启动");
        logInfo("目标窗口: " + windowTitle);
        logInfo("操作间隔: 500秒");
        logInfo("按Ctrl+C终止程序");

        // 创建定时任务调度器
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

        // 定时任务
        scheduler.scheduleAtFixedRate(() -> {
            try {
                HWND hwnd = user32.FindWindow(null, windowTitle);
                if (hwnd != null) {
                    if (activateWindow(hwnd)) {
                        performMouseClick(hwnd);
                        logInfo(String.format("操作成功 (成功: %d, 失败: %d)",
                                successCount.incrementAndGet(),
                                failureCount.get()));
                    } else {
                        logInfo(String.format("窗口激活失败 (成功: %d, 失败: %d)",
                                successCount.get(),
                                failureCount.incrementAndGet()));
                    }
                } else {
                    logInfo(String.format("未找到窗口 (成功: %d, 失败: %d)",
                            successCount.get(),
                            failureCount.incrementAndGet()));
                }
            } catch (Exception e) {
                logError("执行任务时发生错误", e);
                failureCount.incrementAndGet();
            }
        }, 0, 500, TimeUnit.SECONDS);

        // 添加关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            logInfo("程序正在关闭...");
            scheduler.shutdown();
            try {
                if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                    scheduler.shutdownNow();
                }
            } catch (InterruptedException e) {
                scheduler.shutdownNow();
            }
            logInfo(String.format("程序已终止 (总成功: %d, 总失败: %d)",
                    successCount.get(), failureCount.get()));
        }));
    }
} 